using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Data;
using System.Xml;

using NHibernate.Criterion;

using Pampa.CRUD.Core;
using Pampa.CRUD.Exceptions;

using Pampa.Grid.Core;
using Pampa.Grid.Core.Filters;
using Pampa.Grid.Exceptions;

namespace Pampa.Grid.Data
{
    public abstract class GridDataReaderEntityBase : GridDataReader
    {
        protected string entityName;
        protected object[] entities;
        protected int cursor;

        protected GridDataReaderEntityBase() : base()
        {
        }

        protected GridDataReaderEntityBase(string entityName) : base()
        {
            this.entityName = entityName;
        }
        
        #region Properties

        public string EntityName
        {
            get { return entityName; }
        }

        private object CurrentEntity
        {
            get { return this.entities[this.cursor]; }
        }
        
        #endregion

        #region Public Funtions

        public override sealed void Open(Configuration configuration, int pageSize, int pageNumber)
        {
            this.cursor = -1;
            GetEntities(configuration, pageSize, pageNumber);
        }

        public override bool Read()
        {
            this.cursor++;
            return (this.cursor < entities.Length);
        }

        public override int GetCount(Configuration configuration)
        {
            return CountEntities(configuration);
        }

        public override object GetValue(string fieldName)
        {
            try
            {
                return EntityManager.GetPropertyValue(this.CurrentEntity, fieldName);
            }
            catch(PropertyNotFoundException) 
            { 
                throw (new DataReaderException("There is no field defined with name '" + fieldName + "'"));
            }
        }

        public override void Close()
        {
            this.cursor = -1;
            this.entities = null;
        }

        #endregion

        #region Xml Functions

        public override void LoadXml(System.Xml.XmlNode node)
        {
            XmlNamespaceManager nsManager = new XmlNamespaceManager(node.OwnerDocument.NameTable);
            nsManager.AddNamespace("pampa", node.NamespaceURI);

            XmlNode nodeDataSource = node.SelectSingleNode("pampa:DataSource", nsManager);
            if (nodeDataSource == null)
                throw (new GridConfigurationException("Node 'DataSource' was not found into the node 'DataReader'."));

            if (nodeDataSource.Attributes["Name"] == null)
                throw (new GridConfigurationException("Attribute 'Name' can not be found in node 'DataSource'."));

            this.entityName = nodeDataSource.Attributes["Name"].Value.ToString();
        }

        public override void ToXml(ref System.Xml.XmlNode root)
        {
            XmlDocument document = root.OwnerDocument;
            XmlNode nodeDataReader = document.CreateElement("DataReader");
            root.AppendChild(nodeDataReader);

            XmlAttribute attribute;
            attribute = document.CreateAttribute("Type");
            attribute.Value = this.GetType().FullName;
            nodeDataReader.Attributes.Append(attribute);

            XmlNode nodeDataSource = document.CreateElement("DataSource");
            attribute = document.CreateAttribute("EntityName");
            attribute.Value = this.EntityName;
            nodeDataSource.Attributes.Append(attribute);

            nodeDataReader.AppendChild(nodeDataSource);
        }

        #endregion

        #region Abstract Functions

        protected abstract int CountEntities(Configuration configuration);

        protected abstract void GetEntities(Configuration configuration, int pageSize, int pageNumber);
   
        #endregion
    }
}
